﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Text;
using System.Data;
using System.Data.SqlClient;

using JigsawService.Utility;
using JigsawService.Parsers;

namespace JigsawService
{
    public class JigsawBase
    {
        public enum StatusCodes { Parsed, Authenticated, Authorized, Error };
        public enum ResponseCodes { Success, Empty, Error, Exception };
        public enum DataTypes { Int, Number, Text, XML, JSON, DataTable };

        public JigsawBase()
        {

        }

        /// <summary>
        /// Set result for int, number, text, xml, or json
        /// </summary>
        /// <param name="result"></param>
        /// <param name="cutil"></param>
        public void SetSuccessResult(string result, string datatype, APIMessage apimessage)
        {
            apimessage.ResponseCode = ResponseCodes.Success.ToString();
            apimessage.MethodResult = result;

            switch (datatype.ToLower())
            {
                case "int":
                    apimessage.ResponseType = DataTypes.Int.ToString();
                    break;

                case "number":
                    apimessage.ResponseType = DataTypes.Number.ToString();
                    break;

                case "text":
                    apimessage.ResponseType = DataTypes.Text.ToString();
                    break;

                case "xml":
                    apimessage.ResponseType = DataTypes.XML.ToString();
                    break;

                case "json":
                    apimessage.ResponseType = DataTypes.JSON.ToString();
                    break;
            }
        }

        /// <summary>
        /// Set result for DataTable
        /// </summary>
        /// <param name="result"></param>
        /// <param name="cutil"></param>
        public void SetSuccessResult(DataTable result, bool dtflag, APIMessage apimessage)
        {
            if (result != null && result.Rows.Count > 0)
            {
                apimessage.ResponseCode = ResponseCodes.Success.ToString();
                apimessage.ResponseType = DataTypes.XML.ToString();

                XMLUtility xutil = new XMLUtility();
                apimessage.MethodResult = xutil.TableToXml(result, dtflag);
            }
            else
            {
                apimessage.ResponseCode = ResponseCodes.Empty.ToString();
                apimessage.ResponseType = DataTypes.Text.ToString();
                apimessage.MethodResult = "";
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        /// <param name="sutil"></param>
        public void SetErrorResult(string result, APIMessage apimessage)
        {
            apimessage.ResponseCode = ResponseCodes.Error.ToString();
            apimessage.ResponseType = DataTypes.Text.ToString();
            apimessage.MethodResult = apimessage.StateMessage + result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        /// <param name="sutil"></param>
        public void SetExceptionResult(string result, APIMessage apimessage)
        {
            apimessage.ResponseCode = ResponseCodes.Exception.ToString();
            apimessage.ResponseType = DataTypes.Text.ToString();
            apimessage.MethodResult = apimessage.StateMessage + result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public string GetTimeInMilliseconds()
        {
            string timeMils = "";

            DateTime baseTime = new DateTime(1970, 1, 1, 0, 0, 0);
            DateTime currentTime = DateTime.UtcNow;

            TimeSpan timemillisec = currentTime.Subtract(baseTime);
            timeMils = timemillisec.TotalMilliseconds.ToString();

            return timeMils;
        }

        /// <summary>
        /// Executes standard queries, sets results if successful
        /// </summary>
        /// <param name="sqlCmd"></param>
        /// <param name="dbStr"></param>
        /// <param name="apiMsg"></param>
        public void SelectBase(SqlCommand sqlCmd, string dbStr, APIMessage apiMsg)
        {
            SqlConnection sqlConn = new SqlConnection(dbStr);
            try
            {
                using (sqlConn)
                {
                    sqlConn.Open();
                    sqlCmd.Connection = sqlConn;
                    SqlDataAdapter adap = new SqlDataAdapter(sqlCmd);
                    DataTable queryresults = new DataTable();
                    adap.Fill(queryresults);

                    SetSuccessResult(queryresults, true, apiMsg);
                }
            }
            catch (Exception ex)
            {
                // close connection
                if (sqlConn.State == ConnectionState.Open)
                {
                    sqlConn.Close();
                }
                // rethrow error, to be handled at the service level
                throw;
            }
        }

        /// <summary>
        /// Executes standard inserts, updates, and deletes - sets results if successful
        /// </summary>
        /// <param name="sqlCmd"></param>
        /// <param name="dbStr"></param>
        /// <param name="errMsg"></param>
        /// <param name="apiMsg"></param>
        public void ActionBase(string actionType, SqlCommand sqlCmd, string dbStr, string errMsg, APIMessage apiMsg, string globalID)
        {
            SqlConnection sqlConn = new SqlConnection(dbStr);
            sqlConn.Open();
            SqlTransaction sqlTran = sqlConn.BeginTransaction();
            try
            {
                using (sqlConn)
                {
                    sqlCmd.Connection = sqlConn;
                    sqlCmd.Transaction = sqlTran;
                    int cmdResult = sqlCmd.ExecuteNonQuery();
 
                    // insert affects one row, update and delete affect two rows
                    if ((actionType == "insert" && cmdResult == 1) || (actionType != "insert" && cmdResult == 2))
                    {
                        sqlTran.Commit();
                        if (actionType == "insert")
                        {
                            // return new globalid
                            SetSuccessResult(globalID, "text", apiMsg);
                        }
                        else
                        {
                            // return rows affected
                            SetSuccessResult(cmdResult.ToString(), "text", apiMsg);
                        }
                    }
                    else
                    {
                        // rollback transaction, throw appropriate error message
                        sqlTran.Rollback();
                        switch (actionType)
                        {
                            case "insert":
                                errMsg += "Duplicate found - record was not inserted.";
                                break;
                            case "update":
                                errMsg += "Unable to update old record - record was not updated.";
                                break;
                            case "delete":
                                errMsg += "Unable to update old record - record was not deleted.";
                                break;
                        }
                        throw new Exception(errMsg);
                    }
                }
            }
            catch (Exception ex)
            {
                // if connection still open, rollback transaction and close connection
                if (sqlConn.State == ConnectionState.Open)
                {
                    sqlTran.Rollback();
                    sqlConn.Close();
                }
                // rethrow error, to be handled at the service level
                throw;
            }
        }

    }
}